/**
*
*/
package de.yaams.maker.programm.plugins;
import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.Arrays;
import java.util.HashMap;
import org.apache.commons.lang.Validate;
import org.apache.log4j.Level;
import org.ini4j.Wini;
import de.yaams.maker.helper.FileHelper;
import de.yaams.maker.helper.Log;
import de.yaams.maker.helper.NetHelper;
import de.yaams.maker.helper.Setting;
import de.yaams.maker.helper.SystemHelper;
import de.yaams.maker.helper.extensions.ExtentionManagement;
import de.yaams.maker.helper.extensions.IExtension;
import de.yaams.maker.helper.gui.YDialog;
import de.yaams.maker.helper.gui.YEx;
import de.yaams.maker.helper.gui.YMessagesDialog;
import de.yaams.maker.helper.gui.form.FormInfo;
import de.yaams.maker.helper.gui.form.core.FormBuilder;
import de.yaams.maker.helper.language.I18N;
import de.yaams.maker.programm.YAamsCore;
import de.yaams.maker.programm.plugins.PluginInfo.STAGE;
/**
* @author abby
*
*/
public class PluginLoader {
public static File folder;
protected static HashMap<String, PluginInfo> plugins;
private static boolean searchOnline;
// Parameters
@SuppressWarnings("rawtypes")
private static final Class[] parameters = new Class[] { URL.class };
/**
*
*/
public static void init(YMessagesDialog ymd) {
// save settings
ExtentionManagement.add(ExtentionManagement.SAVE, new IExtension() {
@Override
public void work(HashMap<String, Object> objects) {
FileHelper.saveXML(new File(folder, "setting.xml"), plugins);
}
});
// has folder?
if (folder == null) {
folder = new File(YAamsCore.programPath, "Plugins");
}
// check folder
if (!FileHelper.checkPath(folder, ymd, true, true)) {
return;
}
// load active settings
plugins = (HashMap<String, PluginInfo>) FileHelper.loadXML(new File(folder, "setting.xml"));
if (plugins == null) {
plugins = new HashMap<String, PluginInfo>();
}
installOnlineInfo(false);
// extract plugins?
for (File path : folder.listFiles(new FileFilter() {
@Override
public boolean accept(File f) {
return f.getName().toLowerCase().endsWith(".yex");
}
})) {
try {
// get id
String id = PluginLoader.getIDForFile(path);
// create folder
FileHelper.mkdirs(new File(folder, id));
// extract file
FileHelper.extractArchive(path, new File(folder, id));
// delete archiv
FileHelper.deleteFile(path);
// show message
// md.add(I18N.t("Entpacken vom Plugin {0} war erfolgreich.",
// id),
// Level.INFO_INT);
Log.ger.info("Extract " + path);
// mess.add(I18N.t("Extract {0} successful.", id));
} catch (final Throwable t) {
ymd.add(YEx.toString("Can not add Plugin " + path, t, false), Level.WARN_INT);
}
}
HashMap<String, PluginInfo> order = new HashMap<String, PluginInfo>();
// load all plugins from the folder
for (File path : folder.listFiles(new FileFilter() {
@Override
public boolean accept(File f) {
return f.isDirectory();
}
})) {
// exist?
if (!plugins.containsKey(path.getName())) {
plugins.put(path.getName(), new PluginInfo(path));
}
}
// add all existing plugins
for (String key : plugins.keySet()) {
order.put(key, plugins.get(key));
}
// start all plugins
// load plugins
while (true) {
boolean chance = false;
for (String id : order.keySet().toArray(new String[order.keySet().size()])) {
// can start?
STAGE erg = order.get(id).canUse(ymd, order.keySet().toArray(new String[order.keySet().size()]));
// add it?
if (erg == STAGE.USEABLE || erg == STAGE.NOTUSEABLE) {
order.remove(id);
chance = true;
}
}
if (chance == false) {
break;
}
}
// are modules missing?
for (String id : order.keySet()) {
ymd.add(I18N.t("Kann Plugin {0} nicht starten.", order.get(id).getTitle()), Level.INFO_INT);
}
}
/**
* Helpermethod
*
* @param base
*/
public static void addSearchFolder(File base) {
// add it
addFolder(base);
// search für jars inside and it itf
for (File f : Arrays.asList(base.listFiles(new FileFilter() {
@Override
public boolean accept(File f) {
return f.getName().endsWith(".jar") || f.isDirectory();
}
}))) {
// add it
if (f.isDirectory()) {
addSearchFolder(f);
} else {
addFolder(f);
}
}
}
/**
* Add the .jar folder to the class loader
*
* @param u
* @throws IOException
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
protected static void addFolder(final File p) {
Log.ger.info("Add to search path: " + p);
try {
final URL u = p.toURI().toURL();
final URLClassLoader sysLoader = (URLClassLoader) ClassLoader.getSystemClassLoader();
final URL urls[] = sysLoader.getURLs();
for (URL url : urls) {
if (url.toString().equalsIgnoreCase(u.toString())) {
return;
}
}
final Class sysclass = URLClassLoader.class;
try {
final Method method = sysclass.getDeclaredMethod("addURL", parameters);
AccessController.doPrivileged(new PrivilegedAction<Object>() {
@Override
public Object run() {
method.setAccessible(true);
return "";
}
});
method.invoke(sysLoader, new Object[] { u });
} catch (final Throwable t) {
throw new IOException("Error, could not add URL to system classloader", t);
}
} catch (final Throwable t) {
YEx.info("Can not add " + p + " to plugin search path", t);
}
}
/**
* @return the plugins
*/
public static HashMap<String, PluginInfo> getPlugins() {
return plugins;
}
/**
* Is this plugin install?
*
* @param id
* @return
*/
public static boolean isInstall(String id) {
return plugins.containsKey(id) && plugins.get(id).isUseable();
}
/**
* Get this plugin
*
* @return
*/
public static PluginInfo get(String key) {
return plugins.get(key);
}
/**
* Helpermethod to uninstall a plugin
*
* @param key
*/
public static void uninstall(String key) {
// ask user
if (!YDialog.delete(get(key).getTitle(), "plugin")) {
return;
}
// uninstall it
FileHelper.deleteTree(new File(folder, key));
plugins.remove(plugins.get(key));
}
/**
* Look online for the catalog and load it
*
* @param background
*/
public static void installOnlineInfo(boolean manuell) {
// check settings
if (!Setting.get("net.access", true) && !manuell) {
return;
}
File catalog = new File(folder, "catalog.ini");
// update catalog?
if (manuell || Setting.get(PluginPlugin.CHECK, 168) != -1
&& System.currentTimeMillis() - Setting.get("plugins.updateCheck", 0L) >= Setting.get(PluginPlugin.CHECK, 168L) * 3600000) {
Setting.set("plugins.updateCheck", System.currentTimeMillis());
Log.ger.info("Check updates");
// has internet?
if (!NetHelper.hasInternet(manuell)) {
return;
}
// delete file
if (catalog.exists()) {
FileHelper.deleteFile(catalog);
}
// has internet?
String link = NetHelper.getContentAsString("http://www.yaams.de/plugin/?action=catalog");
// dl file?
if (!NetHelper.downloadFile(catalog, link)) {
return;
}
} else {
// no update check?
if (!catalog.exists()) {
Log.ger.info("No update check");
return;
}
}
// exist?
if (!FileHelper.checkPath(I18N.t("Kann Pluginkatalog nicht öffnen"), catalog, false, false)) {
return;
}
try {
FormBuilder f = new FormBuilder("plugin.updates");
// run over all plugins
final Wini ini = new Wini(catalog);
// add all
for (final String id : ini.keySet()) {
// create folder?
File o = new File(new File(folder, id), "online.ini");
if (!o.getParentFile().exists()) {
FileHelper.mkdirs(o.getParentFile());
}
// clear file
if (o.exists()) {
o.delete();
}
o.createNewFile();
// save in folder
Wini out = new Wini(o);
out.add(id, ini.get(id));
out.store();
// exist?
if (!PluginLoader.getPlugins().containsKey(id)) {
PluginLoader.getPlugins().put(id, new PluginInfo(o.getParentFile()));
}
// load online
get(id).checkOnline(ini.get(id), f);
}
// found it?
if (f.getHeader("basic").getElements().size() > 0) {
f.addElement("basic.desc", new FormInfo("", I18N.t("Wähle die Plugins aus, die geupdatet werden sollen.")).setSorting(-1));
YDialog.showForm(I18N.t("Es sind Updates verfügbar"), "plugin_web", f);
SystemHelper.restart();
}
} catch (Throwable t) {
YEx.info("Can not read catalog " + catalog, t);
}
searchOnline = true;
}
/**
* Method to download a plugin
*
* @param key
*/
public static boolean installFromOnline(String id) {
// has online info?
if (!searchOnline) {
installOnlineInfo(true);
}
try {
Validate.notNull(get(id));
} catch (Exception e) {
YEx.warn("Plugin " + id + " not exist.", e);
return false;
}
// dl
NetHelper.downloadFile(new File(PluginLoader.folder, id + ".yex"), get(id).getOnlineElement("download", "No Link"));
return true;
}
/**
* Create from a filename the id
*
* @param name
* @return
*/
public static String getIDForFile(File name) {
String end = name.getName().toLowerCase();
// run over the name and find the positon
for (int i = 0, l = end.length(); i < l; i++) {
if (!Character.isLetter(end.charAt(i))) {
end = end.substring(0, i);
break;
}
}
return end;
}
}